package com.trendata.mina.factory;

/*
 *  Licensed to the Apache Software Foundation (ASF) under one
 *  or more contributor license agreements.  See the NOTICE file
 *  distributed with this work for additional information
 *  regarding copyright ownership.  The ASF licenses this file
 *  to you under the Apache License, Version 2.0 (the
 *  "License"); you may not use this file except in compliance
 *  with the License.  You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing,
 *  software distributed under the License is distributed on an
 *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 *  KIND, either express or implied.  See the License for the
 *  specific language governing permissions and limitations
 *  under the License.
 *
 */

import org.apache.log4j.Logger;
import org.apache.mina.core.buffer.IoBuffer;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.CumulativeProtocolDecoder;
import org.apache.mina.filter.codec.ProtocolDecoderOutput;

/**
 * 处理长数据多次分包的decode
 * 
 * @author: HuangXiuXiu Email:243559392@qq.com
 */
public class BigDataDecoder extends CumulativeProtocolDecoder {
	private static final Logger logger = Logger.getLogger("serverSocketLogger");

	/**
	 * 
	 * 这个方法的返回值是重点：
	 * 
	 * 1、当内容刚好时，返回false，告知父类接收下一批内容
	 * 
	 * 2、内容不够时需要下一批发过来的内容，此时返回false，这样父类 CumulativeProtocolDecoder
	 * 
	 * 会将内容放进IoSession中，等下次来数据后就自动拼装再交给本类的doDecode
	 * 
	 * 3、当内容多时，返回true，因为需要再将本批数据进行读取，父类会将剩余的数据再次推送本
	 * 
	 * 类的doDecode
	 */
	@Override
	protected boolean doDecode(IoSession session, IoBuffer in, ProtocolDecoderOutput out) throws Exception {
		if (in.hasRemaining()) {
			logger.info("开始执行decode");
			// 标记当前位置，以便reset
			in.mark();
			// 获取前10位的作为长度
			byte[] b = new byte[10];
			in.get(b);
			String len = new String(b, "UTF-8");
			int length = stringToInt(len);

			// 如果消息内容不够，会继续从缓存里拉数据，放进in里，重置in
			if (length > in.remaining()) {
				in.reset();
				// 让父类继续给，接收新数据，以拼凑成完整数据
				logger.info("消息长度不够：" + in.remaining());
				return false;
			}
			// 当长度够了的时候
			else {
				logger.info("长度够了");
				byte[] bytes = new byte[length];
				in.get(bytes);
				String str = new String(bytes, "UTF-8");
				if (null != str && str.length() > 0) {
					// 将字符串写到服务器里
					out.write(str);
				}
				// 读完发送长度的字符串发现in里还有内容，说明粘包了,暂时不知道如何处理粘包，也不知道粘包哪来的，所以直接清楚
				if (in.hasRemaining()) {
					logger.info("出现粘包...暂时不处理，直接情况粘包");
					in.clear();
				}
				// 数据读取完成，不继续再给了
				return true;
			}
		}
		logger.info("remaing is null , return fasle");
		// 让父类进行接收下个包
		return false;
	}

	/**
	 * 将10位长的字符串变成数字长度
	 * 
	 * @param str
	 *            10位长的长度
	 * @return
	 */
	private int stringToInt(String str) {
		while (true) {
			if (str.startsWith("0")) {
				str = str.substring(1);
			} else {
				break;
			}
		}
		return Integer.valueOf(str);
	}

}
